import pygame, sys
import os
from catchplayer import Player
from floor import Floor
from ceiling import Ceiling
from random import choice,randint
from liquid import Liquid,Bomb

# initialize the namecard showing
show1 = True
show2 = True
stop = False

# basic functions
def draw_text(text,font,text_col,x,y):
    img = font.render(text, True, text_col) 
    screen.blit(img,(x,y))

# show the charactercard
# the liquid to be held
def show_charactercardl(x,y):
    # delaying setting
    waiting = True
    waited_time = pygame.time.get_ticks()
    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()

        # draw name card
        draw_text('Enzyme',pygame.font.SysFont('Lucida Sans', 12),'white',x-5,y +10)
        draw_text('Pancreatic', pygame.font.SysFont('Lucida Sans', 12), 'white', x-10, y-3)
        pygame.display.update()
        clock.tick(15)
        if pygame.time.get_ticks() - waited_time > 2000:
            waiting = False

# the bomb which can not be collided
def show_charactercardb(x,y):
    waiting = True
    waited_time = pygame.time.get_ticks()
    while waiting:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
        draw_text('Bomb',pygame.font.SysFont('Lucida Sans', 12),'white',x - 1,y + 10)
        pygame.display.update()
        clock.tick(15)
        if pygame.time.get_ticks() - waited_time > 1000:
            waiting = False

class Game:
    def __init__(self):
        self.font = pygame.font.Font(None,40)

        # health & score
        self.lives = 4
        self.live_surf = pygame.image.load('../graphics/live.png').convert_alpha()
        self.live_x_start_pos = screen_width - (self.live_surf.get_size()[0] * 4 + 20) # set a group of lives and draw then on certain positions

        # player setup
        player_sprite = Player((screen_width / 2, screen_height),screen_width,7)
        self.player = pygame.sprite.GroupSingle(player_sprite)

        # floor
        floor_sprite = Floor((screen_width / 2,screen_height),screen_height, screen_width)
        self.floor = pygame.sprite.GroupSingle(floor_sprite)

        # ceiling
        self.ceiling = pygame.sprite.Group()
        self.liquids = pygame.sprite.Group()
        self.bombs = pygame.sprite.Group()
        self.ceiling_setup(rows = 1,cols = 10)
        self.ceiling_direction = 1

    # add ceiling as the generator of liquids and bombs
    # make a row of squares and move them left and right, using the moving to change the position
    def ceiling_setup(self,rows,cols,x_distance = 60, y_distance = 10, x_offset = 15):
        for row_index, row in enumerate(range(rows)):
            for col_index, col in enumerate(range(cols)):
                x = col_index * x_distance + x_offset
                y = row_index * y_distance
                ceiling_sprite = Ceiling(x,y)
                self.ceiling.add(ceiling_sprite)

    # check the position of the ceiling and change the direction when collision happens
    def ceiling_position_checker(self):
        all_ceilings = self.ceiling.sprites()
        for ceiling in all_ceilings:
            if ceiling.rect.right >= screen_width:
                self.ceiling_direction = -1
            elif ceiling.rect.left <= 0:
                self.ceiling_direction =1

    # use python's random function to choose one of the ceilings to drop the liquids
    def liquid_drop(self):
        if self.ceiling.sprites():
            random_ceiling = choice(self.ceiling.sprites())
            liquid_sprite = Liquid(random_ceiling.rect.center,5,screen_height)
            self.liquids.add(liquid_sprite)

    # use python's random function to choose one of the ceilings to drop the bombs
    def bomb_drop(self):
        if self.ceiling.sprites():
            random_ceiling = choice(self.ceiling.sprites())
            random_bspeed = randint(3,8)
            bomb_sprite = Bomb(random_ceiling.rect.center,random_bspeed,screen_height)
            self.bombs.add(bomb_sprite)

    # check the collisions
    def collision_checks(self):
        # liquids
        if self.liquids:
            for liquid in self.liquids:
                if pygame.sprite.spritecollide(liquid,self.floor,False): 
                    liquid.kill() #destroy the laser
                    self.lives -= 1 # sub lives

                if pygame.sprite.spritecollide(liquid,self.player,False): 
                    liquid.kill() # end the game

        # bombs
        if self.bombs:
            for bomb in self.bombs:
                if pygame.sprite.spritecollide(bomb,self.floor,False): 
                    bomb.kill() #destroy the bomb
                if pygame.sprite.spritecollide(bomb,self.player,False):  
                    bomb.kill() 
                    self.lives = -1
    
    def display_lives(self):
        for live in range(self.lives):
            x = self.live_x_start_pos + (live * (self.live_surf.get_size()[0] + 5))
            screen.blit(self.live_surf,(x,8))

    # death: game ending, no life of collide with bomb
    def check_death(self):
        if self.lives <= 0:    
            if self.ceiling:
                for ceiling in self.ceiling:
                    ceiling.kill() # clean all the ceilings on the screen
            screen.fill('black')
            draw_text('TRY AGAIN!',font_big,'white',200,200)
            # exit
            draw_text('PRESS SPACE TO EXIT',font_big,'white',150,300)
            # play again
            draw_text('PRESS ENTER TO PLAY Again',font_big,'white',100,350)
            key = pygame.key.get_pressed()
            if key[pygame.K_SPACE]:
                pygame.quit()
                sys.exit()
            elif key[pygame.K_RETURN]:
                pygame.quit()
                os.system('python main.py')
                quit()

    def run(self):
        # draw the floor(the y bound of the player and the drops(do kill))
        self.floor.draw(screen)
        
        # draw the ceiling
        self.ceiling_position_checker()
        self.ceiling.update(self.ceiling_direction)
        self.ceiling.draw(screen)

        # draw the liquids and bombs
        self.liquids.update()
        self.bombs.update()

        # check the collision and draw the GUI screen
        self.collision_checks()
        self.display_lives()
        self.check_death()

        # update the screen
        self.liquids.draw(screen)
        self.bombs.draw(screen)
        self.player.update()
        self.player.draw(screen)
        
if __name__ == '__main__':
    # basic settings
    pygame.init()
    screen_width = 600
    screen_height = 600
    screen = pygame.display.set_mode((screen_width,screen_height))
    clock = pygame.time.Clock()
    font_big = pygame.font.SysFont('Lucida Sans', 25)
    game = Game()

    # time check andget ticks
    font = pygame.font.Font(None,40)
    start_time = pygame.time.get_ticks()

    # generate the liquid and bomb after certain period
    # however the function is renewing the clock every frame
    LIQUID = pygame.USEREVENT + 1
    pygame.time.set_timer(LIQUID,1250)
    BOMB = pygame.USEREVENT + 3
    pygame.time.set_timer(BOMB,5000)

    while True:
        end_time = pygame.time.get_ticks()
        time = (end_time - start_time) // 1000 # recording seconds

        # here can not use the position check, for the time is always renewing
        # and the function will be called every frame after reachinf certain position
        # here uses the time checker
        if show1 and time == 2: 
            for l in game.liquids:
                if l.rect.y >= screen_height/2:
                    show_charactercardl(l.rect.left, l.rect.top-30)
                    show = False
        if show2 and time == 6:
            for b in game.bombs:
                if b.rect.y >= screen_height/2:
                    show_charactercardb(b.rect.left, b.rect.top-30)
                    show = False

        # using ebent type to call the function of generating drops
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == LIQUID:
                game.liquid_drop()
            if event.type == BOMB:
                game.bomb_drop()  
        
        # win screen 
        def victory_message():
            if game.lives > 0 and time >= 60:
                for ceiling in game.ceiling:
                    ceiling.kill()
                screen.fill('black')
                draw_text('YOU WIN!',font_big,'yellow',200,200)
                draw_text('PRESS SPACE TO EXIT',font_big,'white',150,300)
                draw_text('Press ENTER TO THE NEXT LEVEL',font_big,'white',100,350)
                key = pygame.key.get_pressed()
                if key[pygame.K_SPACE]:
                    pygame.quit()
                    sys.exit()
                elif key[pygame.K_RETURN]:
                    pygame.quit()
                    os.system('cd ../../level_5/mainpy & python main.py')
                    quit()

        # pause function, p for pause and z for continue
        key = pygame.key.get_pressed()
        if key[pygame.K_p]:
            stop = True
        while stop:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
            key = pygame.key.get_pressed()
            if key[pygame.K_z]:
                stop = False

        # draw the screen
        screen.fill((30,30,30))
        game.run()
        victory_message()# be put on the up layer

        # show time
        text_surf = font.render('Time:' + str(time), True, 'blue')
        text_rect = text_surf.get_rect(center = (50, 40))
        screen.blit(text_surf,text_rect)

        pygame.display.update()

        pygame.display.flip()
        clock.tick(60)
